package top.kaoshanji.ch12;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 代码清单 ch12-07：Callable执行器示例(12.6.3节)
 * 并未执行
 * author kaoshanji
 * ^_^
 * create time 2024/11/30 10:41
 */
public class ExecutorDemo {

    private static final Logger logger = LogManager.getLogger(ExecutorDemo.class);

    public static void main(String[] args) throws IOException, InterruptedException, ExecutionException {
        logger.info("...代码清单 ch12-07：Callable执行器示例(12.6.3节)...");

        try (var in = new Scanner(System.in)) {

            System.out.print("Enter base directory (e.g. /opt/jdk-9-src): ");
            String start = in.nextLine();
            System.out.print("Enter keyword (e.g. volatile): ");
            String word = in.nextLine();

            Set<Path> files = descendants(Path.of(start));

            // 任务1
            var tasks = new ArrayList<Callable<Long>>();
            for (Path file: files) {

                // 创建 Callable 对象
                Callable<Long> task = () -> occurrences(word, file);
                tasks.add(task);
            }

            ExecutorService executor = Executors.newCachedThreadPool();
            Instant startTime = Instant.now();

            // 执行给定的任务，返回所有任务的结果
            List<Future<Long>> results = executor.invokeAll(tasks);

            long total = 0;
            for (Future<Long> result: results) {
                total += result.get();
            }

            Instant endTime = Instant.now();
            System.out.println("Occurrences of " + word + ": " + total);
            System.out.println("Time elapsed: " + Duration.between(startTime, endTime).toMillis() + " ms");

            // 任务2
            var searchTasks = new ArrayList<Callable<Path>>();
            for (Path file: files) {
                searchTasks.add(searchForTask(word, file));
            }

            // 执行给定的任务，返回其中一个任务的结果
            Path found = executor.invokeAny(searchTasks);
            System.out.println(word + " occurs in: " + found);

            if (executor instanceof ThreadPoolExecutor) { // the single thread executor isn't
                System.out.println("Largest pool size: " + ((ThreadPoolExecutor) executor).getLargestPoolSize());
            }

            executor.shutdown();

        }

    }

    // 统计单个文件出现关键词的数量
    public static long occurrences(String word, Path path) {

        try (var in = new Scanner(path)) {
            int count = 0;
            while (in.hasNext()) {
                if (in.next().equals(word)) {
                    count++;
                }
            }
            return count;
        } catch (IOException e) {
            return 0;
        }

    }

    // 指定目录下文件集
    public static Set<Path> descendants(Path rootDir) throws IOException {

        try (Stream<Path> entries = Files.walk(rootDir)){
            return entries.filter(Files::isRegularFile).collect(Collectors.toSet());
        }

    }

    // 一个判断文件是否有指定关键词的任务
    public static Callable<Path> searchForTask(String word, Path path) {

        return () -> {
            try (var in = new Scanner(path)){
                while (in.hasNext()) {
                    if (in.next().equals(word)) {
                        return path;
                    }
                    if (Thread.currentThread().isInterrupted()) {
                        System.out.println("Search in " + path + " canceled.");
                        return null;
                    }

                }

                throw new NoSuchElementException();
            }
        };
    }


}
